package io.virtualapp.hook_sdk.firewall;

import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.blankj.utilcode.util.ImageUtils;
import com.taobao.android.dexposed.DexposedBridge;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.URL;
import java.util.ArrayList;
import java.util.Map;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XC_MethodReplacement;
import de.robv.android.xposed.XposedHelpers;

/**
 * 睿易网络连接hooker工具类
 * */
public class RiNetHooker {

    private HookCallBack callBack;

    public RiNetHooker(HookCallBack callBack){
        this.callBack = callBack;
    }

    public void initHooker() {
        int version = android.os.Build.VERSION.SDK_INT;
        Log.e("ZXY","RiNetHooker->initHooker()"+version);
        //当Android版本大于6.0时使用sandhook框架
        //当Android版本小于6.0使用epic框架
        hookScreen();//添加截图水印实现
        hookBlueTooth();//hook蓝牙扫描
        //网络hook
        if (version>=23)
            sandHook();
        else
            dexposedHook();
    }

    //hook蓝牙的扫描
    private void hookBlueTooth() {
        XposedHelpers.findAndHookMethod(android.bluetooth.BluetoothAdapter.class, "startDiscovery", new XC_MethodReplacement() {
            @Override
            protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
                Log.d("ytx", "有人扫描附近的蓝牙设备:禁止 ");
                return null;
            }
        });
    }
    static final WebViewClient nowClient = new WebViewClient(){
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                Log.e("ZXY","client:"+request.getUrl());
                if (request == null)
                    return true;
                if (FireWallConfig.array == null)
                    return true;
                if (FireWallConfig.array.size() == 0)
                    return true;
                String sourceUrl = request.getUrl().toString();
//                String urlStr = sourceUrl.substring(sourceUrl.indexOf("://")+3);
//                int index = urlStr.indexOf("/");
//                if (index<=0)
//                    index = urlStr.length()-1;
//                urlStr = urlStr.substring(sourceUrl.indexOf("."),index);
                String urlStr = null;
                try {
                    urlStr = new URL(sourceUrl).getHost();
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                    urlStr = FireWallConfig.hookUrl;
                }
                ArrayList<AppNetInfo> array = getHost();
                if (FireWallConfig.type == FireWallType.WHITE){
                    for (AppNetInfo info : array){
                        if (info.addressStr.equals(urlStr)) {
                            view.loadUrl(sourceUrl);
                            return true;
                        }
                    }
                    view.loadUrl(FireWallConfig.hookUrl);
                }else if (FireWallConfig.type == FireWallType.BLACK){
                    for (AppNetInfo info : array){
                        if (info.addressStr.equals(urlStr)){
                            view.loadUrl(FireWallConfig.hookUrl);
                            return true;
                        }
                    }
                    view.loadUrl(sourceUrl);
                }
            }
            return true;
        }

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            if (TextUtils.isEmpty(url))
                return true;
            if (FireWallConfig.array == null)
                return true;
            if (FireWallConfig.array.size() == 0)
                return true;
//            int indedx = url.indexOf("://")+3;
//            String urlStr = url;
//            urlStr = urlStr.substring(indedx);
//            urlStr = urlStr.substring(0,urlStr.indexOf("/"));
            String urlStr = null;
            try {
                urlStr = new URL(url).getHost();
            } catch (MalformedURLException e) {
                e.printStackTrace();
                urlStr = FireWallConfig.hookUrl;
            }
            ArrayList<AppNetInfo> array = getHost();
            if (FireWallConfig.type == FireWallType.WHITE){
                for (AppNetInfo info : array){
                    if (info.addressStr.equals(urlStr)) {
                        view.loadUrl(url);
                        return true;
                    }
                }
            }else if (FireWallConfig.type == FireWallType.BLACK){
                for (AppNetInfo info : array){
                    if (info.addressStr.equals(urlStr)){
                        view.loadUrl(FireWallConfig.hookUrl);
                        return true;
                    }
                }
            }
            return true;
        }
    };

    //hook6.0以前网络请求
    private void dexposedHook(){
        Log.e("ZXY","dexposedHook()");
        switch (FireWallConfig.hookType){
            case WEB:
                epicWebView();
                epicWebClient();
                break;
            case HTTP:
                epicOkHttp();
                break;
            case All:
                epicWebView();
                epicWebClient();
                epicOkHttp();
                break;
        }
    }

    private static ArrayList<AppNetInfo> getHost(){
        ArrayList<AppNetInfo> array = new ArrayList<>();
        //数据脱壳操作
        for (int i = 0;i < FireWallConfig.array.size();i ++){
            AppNetInfo info = FireWallConfig.array.get(i);
            //获取域名
            //去掉http://
            String hostName = null;
            try {
                hostName = new URL(null,info.addressStr).getHost();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
            AppNetInfo nowInfo = new AppNetInfo(null,hostName,null);
            array.add(nowInfo);
        }
        return array;
    }

    //hook6.0以后网络请求
    private void sandHook(){
        Log.e("ZXY","sandHook()");
        switch (FireWallConfig.hookType){
            case WEB:
                hookWebView();
                hookWebClient();
                break;
            case HTTP:
                hookOkHttp();
                break;
            case All:
                hookWebView();
                hookWebClient();
                hookOkHttp();
                break;
        }
    }
    //hookWebView方法
    private void epicWebView(){
        DexposedBridge.findAndHookMethod(android.webkit.WebView.class, "loadUrl",String.class,new com.taobao.android.dexposed.XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                super.beforeHookedMethod(param);
                String sourceParam = (String) param.args[0];
                param.args[0] = FireWallUtils.firewallCheck(FireWallConfig.type,sourceParam);
            }
        });
        DexposedBridge.findAndHookMethod(android.webkit.WebView.class, "loadUrl",String.class, Map.class,new com.taobao.android.dexposed.XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                String sourceParam = (String) param.args[0];
                param.args[0] = FireWallUtils.firewallCheck(FireWallConfig.type,sourceParam);
                super.beforeHookedMethod(param);
            }

        });
    }
    //hookwebclient方法
    private void epicWebClient(){
        DexposedBridge.findAndHookMethod(android.webkit.WebView.class, "setWebViewClient", WebViewClient.class,new com.taobao.android.dexposed.XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                param.args[0] = nowClient;
                super.beforeHookedMethod(param);
            }
        });
    }
    //hookOkHttp以及urlconnecttion方法
    private void epicOkHttp(){
        try {
            //hookOKHTTP
            DexposedBridge.findAndHookMethod(Socket.class,"connect", SocketAddress.class,int.class,new com.taobao.android.dexposed.XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    InetSocketAddress address = (InetSocketAddress) param.args[0];
                    String url = address.getAddress().getHostName();
                    if (TextUtils.isEmpty(url))
                        return ;
                    if (FireWallConfig.array == null)
                        return ;
                    if (FireWallConfig.array.size() == 0)
                        return ;
                    String resultURL = FireWallUtils.firewallOkHttpCheck(FireWallConfig.type,url);
//                    Log.e("ZXY","Socket:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
//                    Log.e("ZXY","Socket:"+resultURL);
                    if (resultURL.equals(FireWallConfig.hookUrl)) {
                        InetSocketAddress ia = InetSocketAddress.createUnresolved(FireWallConfig.hookUrl, address.getPort());
                        param.args[0] = ia;
                        Log.e("WM","hook的URL->Socket:"+url);
                    }else {
                        Log.e("TAG","未hook的URL->Socket:"+url);
                    }
                }
            });
        }catch (Exception e){
            Log.e("ZXY","未监测到Okhttp框架");
        }
    }
    //hook截图方法
    private void hookScreen(){
        XposedHelpers.findAndHookMethod(
                android.view.View.class,
                "getDrawingCache",new XC_MethodHook() {

                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        super.beforeHookedMethod(param);
                        Log.e("ZXY","hookScreen()->拦截截图1");
                    }

                    @Override
                    protected void afterHookedMethod(MethodHookParam param)
                            throws Throwable {
                        super.afterHookedMethod(param);
                        Log.e("ZXY","hookScreen()->拦截截图2");
                        Bitmap bitmap = (Bitmap) param.getResult();
                        Log.e("ZXY","hookScreen()->截图添加水印中");
                        param.setResult(ImageUtils.addTextWatermark(bitmap,"MDM", 100,Color.GRAY,bitmap.getWidth()/2-100,bitmap.getHeight()/2-100));
                    }
                });
    }
    //hookWebView方法
    private void hookWebView(){
        XposedHelpers.findAndHookMethod(android.webkit.WebView.class,
                "loadUrl",String.class,new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        String sourceParam = (String) param.args[0];
                        param.args[0] = FireWallUtils.firewallCheck(FireWallConfig.type,sourceParam);
                        param.args[0]="https://www.bwie.net/";
                        Log.e("ZXY","web1:"+sourceParam);
                        super.beforeHookedMethod(param);
                    }
                });
        XposedHelpers.findAndHookMethod(android.webkit.WebView.class, "loadUrl",String.class, Map.class,new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                String sourceParam = (String) param.args[0];
                String url = FireWallUtils.firewallCheck(FireWallConfig.type,sourceParam);
//                param.args[0] = url;
                param.args[0]="https://www.bwie.net/";
                Log.e("ZXY","web2:");
                super.beforeHookedMethod(param);
            }

        });
    }
    //hookwebclient方法
    private void hookWebClient(){
        XposedHelpers.findAndHookMethod(android.webkit.WebView.class,
                "setWebViewClient", WebViewClient.class,new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        param.args[0] = nowClient;
                        super.beforeHookedMethod(param);
                        Log.e("ZXY","webclient");
                    }
                });
    }
    //hookOkHttp以及urlconnecttion方法
    private void hookOkHttp(){
        try {
            XposedHelpers.findAndHookMethod(Socket.class,"connect", SocketAddress.class,int.class,new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    Log.e("ZXY","Socket:");
                    InetSocketAddress address = (InetSocketAddress) param.args[0];
                    String url = address.getAddress().getHostName();
                    Log.e("ZXY","Socket:"+url);
                    if (TextUtils.isEmpty(url))
                        return ;
                    if (FireWallConfig.array == null)
                        return ;
                    if (FireWallConfig.array.size() == 0)
                        return ;
                    String resultURL = FireWallUtils.firewallOkHttpCheck(FireWallConfig.type,url);
                    Log.e("ZXY","Socket:"+url);
                    if (resultURL.equals(FireWallConfig.hookUrl)) {
                        Log.e("ZXY","替换请求地址为百度:");
                        InetSocketAddress ia = InetSocketAddress.createUnresolved(FireWallConfig.hookUrl, address.getPort());
                        param.args[0] = ia;
                    }
                    //插入预警信息
                    if (callBack!=null){
                        callBack.violationUrl(url);
                        callBack = null;
                    }
                    Log.e("ZXY","Socket:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                    super.beforeHookedMethod(param);
                }
            });
        }catch (Exception e){
            Log.e("ZXY","未监测到Okhttp框架");
        }
    }

}
